#ifndef __USEFUL_FUNCTIONS_H__
  #define __USEFUL_FUNCTIONS_H__

#include <string>
#include <list>
#include <fstream>

#include "record_set.h"
#include "smart_array.h"

using namespace std;

void to_html(const record_set &rs, string &output);
void to_string(const record_set &rs, string &output, char column_separator = ',', char row_separator = '\n');
void to_string(const list<string> &l, string &output, char marker = '\'', char separator = ',');

void binary_read(const string &file_name, smart_array<char> &output);
void binary_read(const string &file_name, string &output);
void binary_write(const string &file_name, const string &input, bool append = false);

////
// inlines

bool is_question_mark(const char c);
bool is_apostrophe(const char c);
bool is_odd(const size_t i);
bool is_digit(const char c);
bool is_not_digit(const char c);
bool case_insensitive_char_compare(const char c1, const char c2);

template <class T>
int comparison(const void *p1, const void *p2); // only useful for qsort / bsearch function(s)

template <class T, class U>
bool map_value_compare(const pair<T, U> &p1, const pair<T, U> &p2); // useful with min_element / max_element, for key comparison use C++ less<T> / greater<T>

////
// functor(s)

//! useful in combination with for_each to delete pointers in a collection
struct deleter {
  template <class T>
  void operator()(T *ptr) { delete ptr; }
};

//////////////////////////////////////////////////////////////////////////////

inline bool is_question_mark(const char c) {
  return (c == '?');
} // is_question_mark

inline bool is_apostrophe(const char c) {
  return (c == '\'' || c == '"');
} // is_apostrophe

inline bool is_odd(const size_t i) {
  return ((i % 2) == 1);
} // is_odd

inline bool is_digit(const char c) {
  if (c < '0' || c > '9')
    return false;
  else
    return true;
} // is_digit

inline bool is_not_digit(const char c) {
  return !is_digit(c);
} // is_not_digit

inline bool case_insensitive_char_compare(const char c1, const char c2) {
  return (tolower(c1) == tolower(c2));
} // case_insensitive_char_compare

template <class T>
inline int comparison(const void *p1, const void *p2) {
  const T *a = static_cast<const T*>(p1);
  const T *b = static_cast<const T*>(p2);

  if (*a > *b)
    return 1;
  else if (*a < *b)
    return -1;
  else
    return 0;
} // comparison

template <class T, class U>
inline bool map_value_compare(const pair<T, U> &p1, const pair<T, U> &p2) {
  return (p1.second < p2.second);
} // map_value_compare

#endif
